/**
 * API请求签名工具
 * 用于生成API请求签名，确保请求的安全性和完整性
 */
import md5 from 'js-md5'

// 应用密钥，实际项目中应从环境变量或配置文件中读取
const APP_SECRET = 'mHjeafS8mOWMluadg+';

/**
 * 对象按键名排序
 * @param {Object} obj 需要排序的对象
 * @returns {Object} 排序后的对象
 */
function sortObjectByKeys(obj) {
  return Object.keys(obj)
    .sort()
    .reduce((result, key) => {
      result[key] = obj[key];
      return result;
    }, {});
}

/**
 * 将对象扁平化为一级对象
 * @param {Object} obj 需要扁平化的对象
 * @param {String} prefix 前缀
 * @returns {Object} 扁平化后的对象
 */
function flattenObject(obj, prefix = '') {
  return Object.keys(obj).reduce((acc, key) => {
    const pre = prefix.length ? `${prefix}.` : '';
    
    if (typeof obj[key] === 'object' && obj[key] !== null && !Array.isArray(obj[key])) {
      Object.assign(acc, flattenObject(obj[key], `${pre}${key}`));
    } else if (Array.isArray(obj[key])) {
      // 数组处理
      const arrStr = JSON.stringify(obj[key]);
      acc[`${pre}${key}`] = arrStr;
    } else {
      acc[`${pre}${key}`] = obj[key];
    }
    
    return acc;
  }, {});
}

/**
 * 对象转为URL查询字符串（不含?前缀）
 * @param {Object} obj 需要转换的对象
 * @returns {String} URL查询字符串
 */
function objectToQueryString(obj) {
  return Object.keys(obj)
    .map(key => {
      // 跳过值为null或undefined的参数
      if (obj[key] === null || obj[key] === undefined) return '';
      
      // 编码键和值
      const encodedKey = encodeURIComponent(key);
      const encodedValue = encodeURIComponent(obj[key]);
      // console.log(encodedValue)
      return `${encodedKey}=${encodedValue}`;
    })
    .filter(x => x) // 过滤掉空字符串
    .join('&');
}

/**
 * 生成MD5签名
 * @param {String} str 需要签名的字符串
 * @returns {String} MD5签名
 */
function generateMD5(str) {
  return md5(str).toString();
}

/**
 * 生成SHA1签名
 * @param {String} str 需要签名的字符串
 * @returns {String} SHA1签名
 */
function generateSHA1(str) {
  return CryptoJS.SHA1(str).toString();
}

/**
 * 生成请求签名
 * @param {Object} params 请求参数
 * @param {String} timestamp 时间戳，默认为当前时间戳
 * @param {String} secret 密钥，默认使用APP_SECRET
 * @param {String} signType 签名类型，支持md5和sha1，默认为md5
 * @returns {String} 生成的签名
 */
export function generateSignature(params, timestamp = Date.now(), secret = APP_SECRET, signType = 'md5') {
  // 1. 扁平化和排序参数
  const flatParams = sortObjectByKeys(flattenObject(params));
  
  // 2. 添加时间戳
  flatParams.timestamp = timestamp;
  
  // 3. 转为查询字符串
  const queryString = objectToQueryString(flatParams);
  
  // 4. 拼接密钥
  const stringToSign = `${queryString}&key=${secret}`;
  // console.log(stringToSign)
  // 5. 根据签名类型生成签名
  if (signType === 'sha1') {
    return generateSHA1(stringToSign);
  }
  
  // 默认使用MD5
  return generateMD5(stringToSign);
}

/**
 * 生成带签名的完整参数
 * @param {Object} params 原始参数
 * @param {String} secret 密钥，默认使用APP_SECRET
 * @param {String} signType 签名类型，支持md5和sha1，默认为md5
 * @returns {Object} 包含签名的完整参数
 */
export function getSignedParams(params, secret = APP_SECRET, signType = 'md5') {
  const timestamp = Date.now();
  const signature = generateSignature(params, timestamp, secret, signType);
  
  return {
    ...params,
    timestamp,
    sign: signature,
    sign_type: signType
  };
}

export default {
  generateSignature,
  getSignedParams
};